home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2tup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  21.7 KB  |  754 lines

  1.  
  2. /*====================================================================
  3.  *
  4.  * FILE: prs2tup.c
  5.  *
  6.  * $Header: /private/postgres/src/rules/prs2/RCS/prs2tup.c,v 1.14 1992/07/13 06:10:28 mao Exp $
  7.  *
  8.  * DESCRIPTION:
  9.  * Routines to insert/remove "tuple-level" locks in the tuples of a relation.
  10.  *
  11.  *====================================================================
  12.  */
  13.  
  14. #include "tmp/postgres.h"
  15. #include "nodes/pg_lisp.h"
  16. #include "utils/log.h"
  17. #include "utils/fmgr.h"
  18. #include "executor/execdefs.h"    /* for the EXEC_RESULT */
  19. #include "rules/prs2.h"
  20. #include "rules/prs2stub.h"
  21. #include "rules/rac.h"
  22. #include "parser/parsetree.h"
  23. #include "nodes/primnodes.h"
  24. #include "nodes/primnodes.a.h"
  25. #include "utils/lsyscache.h"
  26. #include "utils/palloc.h"
  27.  
  28. extern LispValue cnfify();
  29. extern bool IsPlanUsingCurrentAttr();
  30. extern LispValue FindVarNodes();
  31. Prs2Stub prs2FindStubsThatDependOnAttribute();
  32.  
  33. /*--------------------------------------------------------------------
  34.  *
  35.  * prs2DefTupleLevelLockRule
  36.  *
  37.  * Read the following at your own risk... If you are not me, then
  38.  * you have my sympathy.
  39.  * 
  40.  * This routine puts "tuple-level" locks to the tuple of a relation.
  41.  *
  42.  * "constQual" is a qualification which involves only
  43.  * attributes of the CURRENT relation (i.e. of the relation to be locked)
  44.  * and constants. (i.e. it has no joins, etc.).
  45.  *
  46.  * Now the tricky part... Which tuples to lock ????
  47.  * Yes, I know, you think that's a trivial question, right?
  48.  * We only need to lock the tuples that satisfy the `constQual', eh?
  49.  * Well, I have bad news for you, my dear hacker, who were naive enough
  50.  * to be dragged into the gloomy world of rules.
  51.  * Consider the following example:
  52.  *
  53.  * RULE 1:    on retrieve to EMP.salary
  54.  *        where current.name = "spyros"
  55.  *        do instead retrieve (salary=1)
  56.  *
  57.  * RULE 2:    on retrieve to EMP.desk
  58.  *        where current.salary = 1
  59.  *        do instead retrieve (desk = "what desk?")
  60.  *
  61.  * Lets say that we have a tuple:
  62.  *   [ NAME    SALARY    DESK  ]
  63.  *   [ spyros    2    steel ]
  64.  * Well, if we define RULE_1 first and RULE_2 second, everything is
  65.  * OK. However, if we define RULE_2 first, then we will NOT put
  66.  * a lock to spyros' tuple, because his salary is 2.
  67.  * So, when later on we define RULE_1 we must put in spyros' tuple not
  68.  * only the locks of RULE_1, but also the locks for RULE_2!
  69.  *
  70.  * To make things even worse, lets rewrite rule 1:
  71.  * RULE 1:    on retrieve to EMP.salary
  72.  *        where current.name = "spyros"
  73.  *        do instead retrieve (E.salary) where E.name = "mike"
  74.  * And lets say that initially mike has a salary equal to 2.
  75.  * Now even if we define RULE_1 first and RULE_2 second, still
  76.  * spyros' tuple will not get any locks. If later on we change mike's
  77.  * salary from 2 to 1, then we are in trouble....
  78.  *
  79.  * So, to cut a long story longer:
  80.  * a) we have to lock all the tuples that satisfy 'constQual' OR
  81.  *    have a "write" lock in any attribute referenced by this 'constQual'
  82.  * b) when we put a lock to a tuple, then if this lock is a "write"
  83.  *    lock (i.e. if our new rule is something like "on retrieve ... do
  84.  *    retrieve" we have also to check all the relation level stub records.
  85.  *    For every stub if its qualification references the attribute
  86.  *    we are currently putting this "write" lock on, then we have also to
  87.  *    add to this tuple the stub's lock...
  88.  *
  89.  *
  90.  * NOTE: If `hintFlag' is false, then we will try to use a tuple level
  91.  * lock, but if we believe that that is not such a good idea after all
  92.  * we return 'false' without doing anything (to indicate that
  93.  * we shopuld use a relation level lock).
  94.  * If 'hintFlag' is true however we go ahead & use a tuple level lock,
  95.  * even if this is going to be really inefficient...
  96.  *--------------------------------------------------------------------
  97.  */
  98.  
  99. bool
  100. prs2DefTupleLevelLockRule(r, hintFlag)
  101. Prs2RuleData r;
  102. bool hintFlag;
  103. {
  104.     LispValue actionPlans;
  105.     LispValue constQual, planQual;
  106.     Relation rel;
  107.     RuleLock relLocks;
  108.     TupleDescriptor tdesc;
  109.     HeapScanDesc scanDesc;
  110.     HeapTuple tuple, newTuple;
  111.     Buffer buffer;
  112.     Prs2Stub oldStubs;
  113.     RuleLock newLocks, thislock, tlocks, newtlocks;
  114.     AttributeNumber *attrList;
  115.     int attrListSize;
  116.     Prs2OneStub oneStub;
  117.     Prs2LockType lockType;
  118.     AttributeNumber attributeNo;
  119.  
  120.     /*
  121.      * We can not use tuple level locks for "on append" rules
  122.      * or for "view" rules.
  123.      */
  124.     if (r->eventType == EventTypeAppend) {
  125.     if (hintFlag) {
  126.         elog(WARN,
  127.         "You can not use `instance-level locks' for `on append' rules");
  128.     } else {
  129.         return(false);
  130.     }
  131.     }
  132.     if (r->actionType == ActionTypeRetrieveValue &&
  133.         r->eventAttributeNumber == InvalidAttributeNumber) {
  134.     if (hintFlag) {
  135.         elog(WARN,
  136.         "You can not use `instance-level locks' for `view' rules");
  137.     } else {
  138.         return(false);
  139.     }
  140.     }
  141.  
  142.     /*
  143.      * First find the constant qual, i.e.a qualification
  144.      * that only involves constants & attributes of the
  145.      * "current" tuple.
  146.      * NOTE: we assume that the varno of the current tuple
  147.      * is a constant (this is hardcoded in the parser).
  148.      */
  149.     constQual = prs2FindConstantQual(r->ruleQual, PRS2_CURRENT_VARNO);
  150.  
  151.     /*
  152.      * If this qual is null, then use relation level locks.
  153.      * Return 'false' to indicate that it is not a good idea to
  154.      * use tuple level locks.
  155.      */
  156.     if (!hintFlag && null(constQual)) {
  157.     return(false);
  158.     }
  159.  
  160.     /*
  161.      * Find all the attributes of the CURRENT tupel 
  162.      * referenced by the the constant qual.
  163.      */
  164.     prs2FindAttributesOfQual(constQual, PRS2_CURRENT_VARNO, 
  165.                 &attrList, &attrListSize);
  166.  
  167.     /*
  168.      * Another reason we should use relation level locks, is if the
  169.      * 'constQual' references an attribute which is calculated by
  170.      * a rule using a relation-level lock. (i.e. if the attribute
  171.      * has a relation level "LockTypeRetrieveWrite" lock.
  172.      */
  173.     rel = ObjectIdOpenHeapRelation(r->eventRelationOid);
  174.     relLocks = prs2GetLocksFromRelation(RelationGetRelationName(rel));
  175.  
  176.     if (prs2LockWritesAttributes(relLocks, attrList, attrListSize)) {
  177.     if (!hintFlag) {
  178.         /*
  179.          * ooops! we have to use a relation level lock.
  180.          */
  181.         RelationCloseHeapRelation(rel);
  182.         return(false);
  183.     } else {
  184.         /*
  185.          * we can't use a relation level lock, because the user
  186.          * wants us to use a tuple level lock (stupid user...)
  187.          * So lets do it!
  188.          * However as we have to lock ALL the tuples currently in
  189.          * the relation and make suer that ALL other tuples
  190.          * appended to the relation will also get the lock,
  191.          * we have to change the 'constQual' to 'nil' (which
  192.          * always evaluates to true).
  193.          */
  194.         constQual = LispNil;
  195.     }
  196.     }
  197.  
  198.     /*
  199.      * OK, go ahead & use tuple level locks....
  200.      *
  201.      * First add the appropriate info to the system catalogs
  202.      * Start with 'pg_prs2rule'... This will give us back the rule oid.
  203.      */
  204.     r->ruleId = prs2InsertRuleInfoInCatalog(r);
  205.  
  206.     /*
  207.      * Now generate & append the appropriate rule plans in the
  208.      * 'pg_prs2plans' relation.
  209.      * NOTE: 'ActionPlanNUmber' is a constant...
  210.      */
  211.     actionPlans = prs2GenerateActionPlans(r);
  212.     prs2InsertRulePlanInCatalog(r->ruleId, ActionPlanNumber, actionPlans);
  213.  
  214.     /*
  215.      * Find what type of lock to use and in which attribute to put it
  216.      */
  217.     prs2FindLockTypeAndAttrNo(r, &lockType, &attributeNo);
  218.  
  219.     /*
  220.      * OK, start putting the rule locks in the tuples of the relation.
  221.      * Yes, yes, we are going to do a sequential scan of the
  222.      * relation, checking ALL the tuples one by one, and if you don't
  223.      * like it, so what? It works and no planner can do better
  224.      * (remember, it is not enough to test the 'constQual'!)
  225.      */
  226.     tdesc = RelationGetTupleDescriptor(rel);
  227.     scanDesc = RelationBeginHeapScan(rel, false, NowTimeQual, 0, NULL);
  228.  
  229.     /*
  230.      * create the new lock (for the new rule).
  231.      */
  232.     thislock = prs2MakeLocks();
  233.     thislock = prs2AddLock(thislock, r->ruleId, lockType,
  234.             attributeNo, ActionPlanNumber,
  235.             0, 0);
  236.  
  237.     /*
  238.      * Find the locks that we must put to the tuple.
  239.      * These locks include of course the 'newLock' but they might also
  240.      * inlcude the locks of all the stubs that "depend" on the
  241.      * attribute locked by 'newlock' iff of course this is a
  242.      * "write" lock...
  243.      */
  244.     oldStubs = prs2GetRelationStubs(r->eventRelationOid);
  245.     if (lockType == LockTypeRetrieveWrite)
  246.     newLocks = prs2FindLocksThatWeMustPut(oldStubs, thislock, attributeNo);
  247.     else
  248.     newLocks = prs2CopyLocks(thislock);
  249.  
  250.     /*
  251.      * Now scan one by one the tuples & put locks to all the
  252.      * tuples that satisfy the qualification, or have a "write"
  253.      * tuple level lock to an attribute referenced by the current
  254.      * "constQual"
  255.      *
  256.      * NOTE: the 'constQual' is the qualification in a 'parsetree'
  257.      * format. In order to call 'prs2StubQualTestTuple' (which in turns
  258.      * calls the executor) we must change it to 'plan' format.
  259.      */
  260.     if (null(constQual)) {
  261.     planQual = LispNil;
  262.     } else {
  263.     planQual = cnfify(constQual,true);
  264.     fix_opids(planQual);
  265.     }
  266.  
  267.     while((tuple = HeapScanGetNextTuple(scanDesc, false, &buffer)) != NULL) {
  268.     /*
  269.      * find the already existing locks of this tuple.
  270.      */
  271.     tlocks = prs2GetLocksFromTuple(tuple, buffer);
  272.     /*
  273.      * NOTE: the first test (planQual==lispNil) is not really
  274.      * required, because 'prs2StubQualTestTuple' will succeed
  275.      * if called with a nil qual, but we do it for efficiency
  276.      * (what a joke!)
  277.      */
  278.     if (planQual == LispNil
  279.        ||prs2LockWritesAttributes(tlocks, attrList, attrListSize)
  280.        || prs2StubQualTestTuple(tuple, buffer, tdesc, planQual)) {
  281.         /*
  282.          * yes!
  283.          * Create a new tuple (i.e. a copy of the old tuple with the
  284.          * new lock, and replace the old tuple).
  285.          * NOTE: do we really need to make that copy ???
  286.          */
  287.         newTuple = palloctup(tuple, buffer, rel);
  288.         newtlocks = prs2LockUnion(tlocks, newLocks);
  289.         prs2PutLocksInTuple(newTuple, InvalidBuffer, rel, newtlocks);
  290.         RelationReplaceHeapTuple(rel, &(tuple->t_ctid),
  291.                     newTuple, (double *)NULL);
  292.         /*
  293.          * Free all new tuples/locks.
  294.          */
  295.         prs2FreeLocks(newtlocks);
  296.         pfree((Pointer)newTuple);
  297.     }
  298.     /*
  299.      * free the `tlocks' to avoid memory leaks
  300.      * (remember: 'prs2GetLocksFromTuple' always
  301.      * return some new, freshly palloced memory)
  302.      *
  303.      * Do NOT free `tuple' because it is probably a pointer
  304.      * to a buffer page and not to 'palloced' data.
  305.      */
  306.     prs2FreeLocks(tlocks);
  307.     }
  308.  
  309.     /*
  310.      * But don't forget to put the relation level stub !
  311.      * NOTE: we can not use the qualification as produced by the
  312.      * parser. We have to preprocess it a little bit...
  313.      *
  314.      * NOTE: the lock of this stub is the original lock for this
  315.      * rule only and NOT the locks that we put in the
  316.      * tuples (which contain the original lock + locks
  317.      * for all other rules that depend on the one we define)!
  318.      */
  319.     oneStub = prs2MakeOneStub();
  320.     oneStub->ruleId = r->ruleId;
  321.     oneStub->stubId = (Prs2StubId) 0;
  322.     oneStub->counter = 1;
  323.     oneStub->lock = thislock;
  324.     oneStub->qualification = planQual;
  325.     prs2AddRelationStub(rel, oneStub);
  326.  
  327.     /*
  328.      * OK, we are done, cleanup & return true...
  329.      */
  330.     RelationCloseHeapRelation(rel);
  331.     HeapScanEnd(scanDesc);
  332.     if (attrList != NULL)
  333.     pfree((Pointer)attrList);
  334.     pfree((Pointer)thislock);
  335.     pfree((Pointer)newLocks);
  336.     return(true);
  337. }
  338.  
  339. /*----------------------------------------------------------------------
  340.  * prs2FindLocksThatWeMustPut
  341.  *
  342.  * (I like that name.... I couldn't find a better one though...)
  343.  *
  344.  * Given some relation stubs and that the given attribute
  345.  * is going to be locked by a 'LockTypeReplaceWrite' lock,
  346.  * find all the new locks that the tuple must get.
  347.  * 
  348.  * More precisely when we add such a lock to an attribute,
  349.  * we have to find all the stubs that their qualification
  350.  * references this attribute, and add their locks to the se
  351.  * of the new locks for that tuple.
  352.  * As these locks can be of 'LockTypeReplaceWrite' we have
  353.  * to repeat this procedure for every such new lock.
  354.  *
  355.  *----------------------------------------------------------------------
  356.  */
  357. RuleLock
  358. prs2FindLocksThatWeMustPut(stubs, newlock, attrno)
  359. Prs2Stub stubs;
  360. RuleLock newlock;
  361. AttributeNumber attrno;
  362. {
  363.     RuleLock resultLocks;
  364.     RuleLock thisLock;
  365.     Prs2Stub s;
  366.     int i;
  367.  
  368.  
  369.     /*
  370.      * find the stubs that depend on this 'attrno'
  371.      */
  372.     s = prs2FindStubsThatDependOnAttribute(stubs, attrno);
  373.  
  374.     /*
  375.      * the locks that we must finally put is the 'newlock'
  376.      * and all the locks of the stubs that depend on this
  377.      * attribute.
  378.      */
  379.     resultLocks = prs2CopyLocks(newlock);
  380.     for (i=0; i<s->numOfStubs; i++) {
  381.     thisLock = s->stubRecords[i]->lock;
  382.     resultLocks = prs2LockUnion(resultLocks, thisLock);
  383.     }
  384.  
  385.     return(resultLocks);
  386. }
  387.     
  388. /*------------------------------------------------------------------------
  389.  * prs2FindStubsThatDependOnAttribute
  390.  *
  391.  * Given some stub records, return all the stubs that "depend" on the
  392.  * given attribute.
  393.  * A stub "depends" on the attribute if
  394.  * a) it references in its qualification this attribute
  395.  * b) refernces an attribute, where another second stub might place
  396.  * a "write" lock, and this second stub "depends" on the original
  397.  * attribute.
  398.  *------------------------------------------------------------------------
  399.  */
  400. Prs2Stub
  401. prs2FindStubsThatDependOnAttribute(stubs, attrno)
  402. Prs2Stub stubs;
  403. AttributeNumber attrno;
  404. {
  405.     
  406.     bool *stubUsed;
  407.     int i, j;
  408.     Prs2OneStub thisStub;
  409.     RuleLock thisStubLock;
  410.     Prs2Stub result;
  411.     List attrlist;
  412.     AttributeNumber thisattrno;
  413.  
  414.     /*
  415.      * 'stubUsed' is an array whith one entry per stub record.
  416.      * If the entry is true, then we have already used this
  417.      * stub record, so there is no need to 
  418.      * check it again....
  419.      */
  420.     if (stubs->numOfStubs > 0) {
  421.     stubUsed = (bool *) palloc(sizeof(bool) * stubs->numOfStubs);
  422.     for (i=0; i<stubs->numOfStubs; i++) {
  423.         stubUsed[i] = false;
  424.     }
  425.     }
  426.  
  427.     /*
  428.      * 'result' is the stubs that depend on "attrno"
  429.      * 'attrList' is a list of the attributes to be examined.
  430.      */
  431.     result = prs2MakeStub();
  432.  
  433.     /*
  434.      * I hate that, but I had to use a lisp list!
  435.      */
  436.     attrlist = lispCons(lispInteger((int)attrno), LispNil);
  437.  
  438.     /*
  439.      * now the loop... One by one examine all the stubs.
  440.      * and add the appropriate stubs to "result".
  441.      */
  442.     while (!null(attrlist)) {
  443.     /*
  444.      * get the first attribute to be examined, & remove it
  445.      * from the list
  446.      */
  447.     thisattrno = (AttributeNumber) CInteger(CAR(attrlist));
  448.     attrlist = CDR(attrlist);
  449.     for (i=0; i<stubs->numOfStubs; i++) {
  450.         if (!stubUsed[i]) {
  451.         /*
  452.          * does this stub depend on the attribute
  453.          * we are currently examining ?
  454.          */
  455.         thisStub = stubs->stubRecords[i];
  456.         thisStubLock = thisStub->lock;
  457.         if (prs2DoesStubDependsOnAttribute(thisStub, thisattrno)) {
  458.             /*
  459.              * add this stub to the 'result'
  460.              */
  461.             prs2AddOneStub(result, thisStub);
  462.             stubUsed[i] = true;
  463.             /*
  464.              * if the stub locks contain a  "write" lock,
  465.              * add the locked attribute to the list
  466.              * of attributes to be examined...
  467.              */
  468.             for (j=0; j<prs2GetNumberOfLocks(thisStubLock); j++){
  469.             Prs2OneLock l;
  470.             Prs2LockType lt;
  471.             AttributeNumber a;
  472.             l = prs2GetOneLockFromLocks(thisStubLock,j);
  473.             lt = prs2OneLockGetLockType(l);
  474.             a = prs2OneLockGetAttributeNumber(l);
  475.             if (lt==LockTypeRetrieveWrite) {
  476.                 attrlist = lispCons(lispInteger((int)a),attrlist);
  477.             }
  478.             }/*for*/
  479.         }/*if*/
  480.         }/*if*/
  481.     } /* for */
  482.     } /* while */
  483.  
  484.     /*
  485.      * clean up...
  486.      */
  487.     if (stubs->numOfStubs > 0) 
  488.     pfree(stubUsed);
  489.  
  490.      /*
  491.       * return the result stubs
  492.       */
  493.     return(result);
  494. }
  495.     
  496.  
  497. /*------------------------------------------------------------------------
  498.  * prs2DoesStubDependsOnAttribute
  499.  * 
  500.  * return true iff 'stub' "depends" on attribute 'attrno', i.e. 
  501.  * if this attribute is used in the stub's qualification.
  502.  *------------------------------------------------------------------------
  503.  */
  504. bool
  505. prs2DoesStubDependsOnAttribute(onestub, attrno)
  506. Prs2OneStub onestub;
  507. AttributeNumber attrno;
  508. {
  509.     LispValue qual;
  510.     AttributeNumber *attrList;
  511.     int attrListSize;
  512.     int i;
  513.     bool res;
  514.  
  515.     qual = onestub->qualification;
  516.  
  517.     prs2FindAttributesOfQual(qual, PRS2_CURRENT_VARNO,
  518.             &attrList, &attrListSize);
  519.  
  520.     res = false;
  521.     for (i=0; i<attrListSize; i++) {
  522.     if (attrList[i] == attrno) {
  523.         res = true;
  524.         break;
  525.     }
  526.     }
  527.             
  528.     if (attrList != NULL)
  529.     pfree((Pointer)attrList);
  530.     return(res);
  531.  
  532. }
  533.  
  534. /*------------------------------------------------------------------------
  535.  * prs2LockWritesAttributes
  536.  *
  537.  * return true if among the rule locks is a "write" lock that
  538.  * "writes" any of the attributes given.
  539.  *------------------------------------------------------------------------
  540.  */
  541. bool
  542. prs2LockWritesAttributes(locks, attrList, attrListSize)
  543. RuleLock locks;
  544. AttributeNumber *attrList;
  545. int attrListSize;
  546. {
  547.  
  548.     register int i, j;
  549.     register AttributeNumber attrno;
  550.     Prs2OneLock oneLock;
  551.  
  552.     for (i=0; i< prs2GetNumberOfLocks(locks); i++) {
  553.     oneLock = prs2GetOneLockFromLocks(locks, i);
  554.     if (prs2OneLockGetLockType(oneLock) == LockTypeRetrieveWrite) {
  555.         attrno = prs2OneLockGetAttributeNumber(oneLock);
  556.         for (j=0; j<attrListSize; j++) {
  557.         if (attrno == attrList[j]) {
  558.             return(true);
  559.         }
  560.         }/*foreach*/
  561.     }/*if*/
  562.     }/*for*/
  563.  
  564.     return(false);
  565. }
  566.  
  567. /*------------------------------------------------------------------------
  568.  * prs2FindAttributesOfQual
  569.  *
  570.  * Given a qualification, return a lsit of all the attributes
  571.  * of the given "varno" used in this qual.
  572.  * This list is actually a "palloced" array of AttributeNumbers.
  573.  *
  574.  * NOTE: duplicates are not removed...
  575.  *------------------------------------------------------------------------
  576.  */
  577. void
  578. prs2FindAttributesOfQual(qual, varno, attrListP, attrListSizeP)
  579. LispValue qual;
  580. int varno;
  581. AttributeNumber **attrListP;
  582. int *attrListSizeP;
  583. {
  584.     LispValue varnodes, t;
  585.     Var v;
  586.     int i,n;
  587.     AttributeNumber *a;
  588.     
  589.     /*
  590.      * first find the Var nodes of the qual
  591.      */
  592.     varnodes = FindVarNodes(qual);
  593.  
  594.     /*
  595.      * first count the attributes
  596.      */
  597.     n = 0;
  598.     foreach(t, varnodes) {
  599.     v = (Var) CAR(t);
  600.     if (get_varno(v) == varno)
  601.         n++;
  602.     }
  603.  
  604.     /*
  605.      * allocate memory for the array.
  606.      */
  607.     if (n>0) {
  608.     a = (AttributeNumber *) palloc(n * sizeof(AttributeNumber));
  609.     if (a==NULL) {
  610.         elog(WARN, "prs2FindAttributesOfQual: Out of memory");
  611.     }
  612.     } else {
  613.     a = NULL;
  614.     }
  615.  
  616.     /*
  617.      * Now fill-in the array...
  618.      */
  619.     i=0;
  620.     foreach(t, varnodes) {
  621.     v = (Var) CAR(t);
  622.     if (get_varno(v) == varno) {
  623.         a[i] = get_varattno(v);
  624.         i++;
  625.     }
  626.     }
  627.  
  628.     /*
  629.      * now return the right values...
  630.      */
  631.     *attrListP = a;
  632.     *attrListSizeP = n;
  633. }
  634.  
  635. /*------------------------------------------------------------------------
  636.  * prs2UndefTupleLevelLockRule
  637.  *
  638.  * remove all the locks & stubs a rule implemented with a tuple level
  639.  * lock. Remove all system catalog info too...
  640.  *------------------------------------------------------------------------
  641.  */
  642. void
  643. prs2UndefTupleLevelLockRule(ruleId, relationOid)
  644. ObjectId ruleId;
  645. ObjectId relationOid;
  646. {
  647.     
  648.     /*
  649.      * remove all its locks/stubs
  650.      */
  651.     prs2RemoveTupleLeveLocksAndStubsOfManyRules(relationOid, &ruleId, 1);
  652.  
  653.     /*
  654.      * remove info from the system catalogs
  655.      */
  656.     prs2DeleteRulePlanFromCatalog(ruleId);
  657.     prs2DeleteRuleInfoFromCatalog(ruleId);
  658.  
  659. }
  660.  
  661. /*------------------------------------------------------------------------
  662.  * prs2RemoveTupleLevelLocksAndStubsOfManyRules
  663.  *
  664.  * remove all the locks & stubs of the rules specified.
  665.  * Do NOT update the system catalogs...
  666.  *
  667.  * We have this routine because sometimes we might to change
  668.  * many tuple-level-lock rules to relation-level-lock.
  669.  * If we do it separatelly for every rule we have two problmes:
  670.  *
  671.  * a) efficiency (one scan versus one scan per rule)
  672.  * b) all these scans run under the same Xid & Cid, therefore we
  673.  * are screwed, because we can not see the previous updates!
  674.  *------------------------------------------------------------------------
  675.  */
  676. void
  677. prs2RemoveTupleLeveLocksAndStubsOfManyRules(relationOid, ruleIds, nrules)
  678. ObjectId relationOid;
  679. ObjectId *ruleIds;
  680. int nrules;
  681. {
  682.     
  683.     bool status;
  684.     Relation rel;
  685.     HeapTuple tuple, newTuple;
  686.     Buffer buffer;
  687.     TupleDescriptor tdesc;
  688.     HeapScanDesc scanDesc;
  689.     RuleLock tlocks;
  690.     Prs2Stub stubs;
  691.     int i;
  692.  
  693.     /*
  694.      * OK, first remove all the stubs for these rules
  695.      */
  696.     stubs = prs2GetRelationStubs(relationOid);
  697.     for (i=0; i<nrules; i++) {
  698.     status =  prs2RemoveStubsOfRule(stubs, ruleIds[i]);
  699.     if (!status) {
  700.         /*
  701.          * something smells fishy here...
  702.          * that means that the rule didnt have any stubs,
  703.          * so it wasn't a tuple-level-lock rule...
  704.          */
  705.         elog(WARN,
  706.     "prs2RemoveTupleLevelLocksOfManyRules: rule %d is not tuple-level-lock"
  707.         ,ruleIds[i]);
  708.     }
  709.     }
  710.  
  711.     /*
  712.      * Now update the stub records for the relation.
  713.      */
  714.     prs2ReplaceRelationStub(relationOid, stubs);
  715.  
  716.     /*
  717.      * now remove all locks for this rule from the tuples of the
  718.      * relation...
  719.      */
  720.     rel = ObjectIdOpenHeapRelation(relationOid);
  721.     tdesc = RelationGetTupleDescriptor(rel);
  722.     scanDesc = RelationBeginHeapScan(rel, false, NowTimeQual, 0, NULL);
  723.  
  724.     while((tuple = HeapScanGetNextTuple(scanDesc, false, &buffer)) != NULL) {
  725.     tlocks = prs2GetLocksFromTuple(tuple, buffer);
  726.     status = false;
  727.     for (i=0; i<nrules;  i++) {
  728.         if (prs2RemoveAllLocksOfRuleInPlace(tlocks, ruleIds[i]))
  729.         status = true;
  730.     }
  731.     if (status) {
  732.         /*
  733.          * the locks of this tuple have changed.
  734.          * replace it...
  735.          */
  736.         newTuple = palloctup(tuple, buffer, rel);
  737.         prs2PutLocksInTuple(newTuple, InvalidBuffer, rel, tlocks);
  738.  
  739.         RelationReplaceHeapTuple(rel, &(tuple->t_ctid),
  740.                     newTuple, (double *)NULL);
  741.         pfree((Pointer)newTuple);
  742.     }
  743.     /*
  744.      * free the `tlocks' (because `prs2GetLocksFromTuple'
  745.      * always return a copy of the locks.
  746.      */
  747.     prs2FreeLocks(tlocks);
  748.     }
  749.  
  750.     RelationCloseHeapRelation(rel);
  751.     HeapScanEnd(scanDesc);
  752. }
  753.     
  754.